package cn.fleamarket.cache;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author zyc
 * @date 2022/6/17 17:05
    需要添加的依赖
        <!--spring面向切面依赖-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.1.6.RELEASE</version>
        </dependency>
        <!--Redis的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        启动类上需要加的注解
        @EnableAspectJAutoProxy  //让切面AOP生效

 */
@Aspect
@Component
public class CacheAspect {

    private static final String REDIS_PREFIX = "FleaMarket:";

    @Autowired
    RedisTemplate redisTemplate;

    @Around("@annotation(Cache)")
    public Object cacheAround(ProceedingJoinPoint jp) throws Throwable {
        // 获取类名
        String className = jp.getTarget().getClass().getSimpleName();
        // 获取目标对象的方法
        MethodSignature methodSignature = (MethodSignature) jp.getSignature();
        Method method = methodSignature.getMethod();
        // 获取一下方法上的cache注解对象
        Cache cache = method.getAnnotation(Cache.class);
        // 获取注解中的值  value缓存时间
        String value = cache.value();
        // 获取目标对象的参数
        String args = Arrays.toString(jp.getArgs());
        // 拼接一个缓存的key
        String key = REDIS_PREFIX + className + ":" + method.getName() + ":" + args;
        // 先从缓存中获取对象
        Object result = redisTemplate.opsForValue().get(key);
        System.out.printf("从缓存中获取的数据:key=%s,value=%s\n",key,result);
        if (Objects.isNull(result)) {
            // 缓存中没有数据，让目标方法继续执行，从数据库查询
            System.out.println("远程调用或者从数据库查\n");
            result = jp.proceed();
            // 放入缓存
            redisTemplate.opsForValue().set(key, result, Long.parseLong(value), TimeUnit.SECONDS);
        }
        return result;

    }
}
